//--------------------------------------------------------------------------------
// This file is a portion of the D2D1Renderer.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Mirco Timmermann
//
//--------------------------------------------------------------------------------
#include "TreeList.h"

namespace D2 {

TreeList::TreeList(int x, int y, int width, int height) : DisplayObject(x, y, width, height) {
	showDoubleSelected = true;
    showSelected = true;
    
   // _flashSelectCounter = 0;
    
    _currentSelectIndex = -1;
    _currentDoubleClickIndex = -1;
    _currentMouseOverIndex = -1;
    _currentDragIndex = -1;
    _currentMouseOverSector = -1;
    
    
	_mouseSelectElement = 0;
	_mouseDoubleClickElement = 0;
	_mouseOverElement = 0;
	_mouseDragElement = 0;
    
    _elementHeight = 20;
    _totalElementHeight = 0;
    
   // _elements = new Array();
    _offsetIndex = 0;
    
    //_radius = 3;
    permanentUpdate = false;
    
    enableInnerDrag = false;
    
//////////////SAME AS LIST.JS
    
    //TODDO:gucken ob gebaurcht wird
    numElements = 0;

	//
	this->open = true;
}

TreeList::~TreeList(void) {

}

/////////////////////////////////

void TreeList::OnMouseDown0(const MouseEvent &e) {
	_mouseSelectElement = _mouseOverElement;

	if(_mouseSelectElement != 0) {
		_currentSelectIndex = _currentMouseOverIndex;
           
		//var evt = new DataEvent("MOUSE_DOWN_ELEMENT", _mouseSelectElement, this, e);
		//this.dispatchEvent(evt);
	}
}

void TreeList::OnMouseOut(const MouseEvent &e) {

}

void TreeList::OnMouseMove(const MouseEvent &e) {
	D2D1_POINT_2F point = this->globalToLocal(e._stageX, e._stageY);

	int index = GetIndex(point.y);

	//determine the current Over Index and current Over Element.
	if(index >= _offsetIndex && index < (_offsetIndex + numElements)) {
		_currentMouseOverIndex = index;
            
		TreeListNode* node = GetNode(_currentMouseOverIndex);
        _mouseOverElement = node;
         
		if(_currentDragIndex == -1) {
			//document.body.style.cursor = "default";

			if(node->hasChilds()) {
				//document.body.style.cursor = "pointer"; //no-drop
            }

		}
	} else {
		_currentMouseOverIndex = -1;
	}
        
//determine the current mouse over sector (for innerDrag)
	int yPos = (_elementHeight*index);
        
	int newY = point.y - yPos;
	int sectorsSize = _elementHeight/3;
         
	int sectorIndex = floor(newY/sectorsSize);        
	_currentMouseOverSector = sectorIndex;   
//
	//var evt = { type:"MOUSE_OVER_ELEMENT", data: this._currentMouseOverIndex, target: this };
	//this.dispatchEvent(evt);
}

void TreeList::OnMouseDrag0(const MouseEvent &e) {

}

void TreeList::OnMouseLeave0(const MouseEvent &e) {

}

void TreeList::OnMouseUp0(const MouseEvent &e) {

}

void TreeList::OnMouseDoubleClick0(const MouseEvent &e) {
	_mouseDoubleClickElement = _mouseOverElement;
       
	if(_mouseDoubleClickElement != 0) {
		_currentDoubleClickIndex = _currentMouseOverIndex;
            
		if(_mouseDoubleClickElement->hasChilds()) {
			_mouseDoubleClickElement->open = !_mouseDoubleClickElement->open;
                        
			//recaluculate the total height;
			//this.UpdateHeight();
			//this.UpdateParent();
                        
			//var evt = new DataEvent("HEIGHT_CHANGED", this._totalElementHeight, this, event);
           // this.dispatchEvent(evt);
		}
           
		//var evt2 = new DataEvent("MOUSE_DOUBLE_CLICK_ELEMENT", this._mouseDoubleClickElement, this, event);
		//this.dispatchEvent(evt2);
	}
}

void TreeList::OnAdded(const Event &e) { 

}

////////////////////////////////////////////////

	/* (picking)
	* returns the current hitten time on position.
	*/
	int TreeList::GetIndex(float y) {
		int index = floor(y/_elementHeight);

		return index + _offsetIndex;
	}

	/*
	* returns the element on the index.
	*/
	TreeListNode* TreeList::GetNode(int index) {
		int eCount = 0;

		return ParseObjectTree_getNode(this, index).node;
	}

	/* (traverse)
    * returns the object on which the index are shown.
    * 
    * element -> default = root-element; (for recursion)
    * elementCount -> default = 0; (for recursion)
    * index -> the index where we want to have the element.
    */
    TreeList::NodeIterateInfo TreeList::ParseObjectTree_getNode(TreeListNode* node, int index, NodeIterateInfo info) {
        //if the index was found return the element.
        if(index == info.index) {
			info.node = node;
            return info;
        }

        info.index++;

        //
        std::vector<TreeListNode*> childs = node->_childs;
        if(childs.size() != 0 && node->open) {
            for(int i = 0; i < childs.size(); i++) {
                TreeListNode* child = childs[i];
                info = ParseObjectTree_getNode(child, index, info);

                //if the element which was return is an object, element with the given index was found.
                if(info.node != 0) {
                    return info;
                }
            }
        }
        
        return info;
    }

/////////////////////////////DATA////////////////////////////

bool TreeList::Draw(Direct2DContext* ctx, D2D1::Matrix3x2F* mtx) {
	if(permanentUpdate) {
		UpdateHeight(); //TODO: wegmachen nicht optimal (performance)
	}

	//ctx->_disableCamera = true;

	//background
	ctx->SetFillStyle(0.3f, 0.3f, 0.3f);
	ctx->rect(0, 0, _width, _height);
	ctx->fill();

	//
	if((!showSelected && _currentMouseOverIndex != -1) || (_currentMouseOverIndex != -1 && _currentMouseOverIndex != _currentSelectIndex)) {
		ctx->SetFillStyle(0.7f, 0.7f, 0.7f);
		ctx->rect(5, (_elementHeight*_currentMouseOverIndex), _width - 10, _elementHeight);
		ctx->fill();
	}

	//draw current Selected Background.
    if(_currentSelectIndex != -1 && _currentDoubleClickIndex != _currentSelectIndex) {
		if(showSelected) {
			ctx->SetFillStyle(0.9f, 0.9f, 0.9f);
			ctx->rect(5, (_elementHeight*_currentSelectIndex), _width - 10, _elementHeight);
			ctx->fill();
		}
	}

	if(_currentDoubleClickIndex != -1) {
		ctx->SetFillStyle(0.4f, 0.4f, 0.4f);
        ctx->rect(5, (_elementHeight*_currentDoubleClickIndex), _width - 10, _elementHeight);
        ctx->fill();

			/*
        if(!showDoubleSelected) {
			_flashSelectCounter++;
			if(_flashSelectCounter > 5) {
				_flashSelectCounter = 0;
				_urrentDoubleClickIndex = -1;
			}
		}
			*/
	}

	//draw element texts.
	ctx->SetFillStyle(0.8f, 0.8f, 0.8f);
	//ctx.font = this.guiStyle.font;

	/*
	for(unsigned int i = 0; i < _elements.length; i++) {
		var element = _elements[i];
            
		//start with root-element.
		//numElements = ParseObjectTree_draw(element, ctx, 0, 0);
	}
	*/
	numElements = ParseObjectTree_draw(this, ctx, 0, 0);

	//DRAW INNER DRAG
	/*
	if(enableInnerDrag && _mouseDragElement != null) {
		if(this._currentMouseOverSector != -1) {
                var yPos_element = (this._elementHeight*this._currentMouseOverIndex);
                var sectorsSize = this._elementHeight/3;
                var yPos_sector = (sectorsSize*this._currentMouseOverSector);
                
                if(this._currentMouseOverSector == 0) {
                    ctx.strokeStyle = "#FFFF00";
                    ctx.beginPath();

                    ctx.moveTo(5, yPos_element + yPos_sector);
                    ctx.lineTo(this.width-5, yPos_element + yPos_sector);

                    ctx.stroke();
                }
                
                if(this._currentMouseOverSector == 1) {
                    ctx.strokeStyle = "#FFFF00";
                    
                    ctx.strokeRect(5, yPos_element, this.width-10, this._elementHeight);
                }
                
                if(this._currentMouseOverSector == 2) {
                    ctx.strokeStyle = "#FFFF00";
                    ctx.beginPath();

                    ctx.moveTo(5, yPos_element + yPos_sector + sectorsSize);
                    ctx.lineTo(this.width-5, yPos_element + yPos_sector + sectorsSize);

                    ctx.stroke();
                }
            }
            
            
            //_currentMouseOverIndex
        }
    }
	*/

	//ctx->_disableCamera = false;

	return true;
}

	void TreeList::UpdateHeight() {
		/*
        _height = CalculateTotalElementsHeight();
        
        var event = { type:"HEIGHT_CHANGED", data: this._totalElementHeight, target: this };
        this.dispatchEvent(event);
		*/
    }

	/* (traverse)
	* draws all _elements.
    */
    int TreeList::ParseObjectTree_draw(TreeListNode* node, Direct2DContext* ctx, int elementCount, int level) {
        bool isElementOpen = node->open;
		bool hasChilds = node->_childs.size() != 0;
        int liftUp = 0; //TODO: nicht konsistent mit HTML5 ... der text muss bei HTML5 verschoben werden um 15.

        elementCount += 1;

        if(hasChilds) {
            ctx->SetFillStyle(0.9f, 0.9f, 0.9f);
            //ctx.font = 11 + "pt Calibri";
            if(isElementOpen) {
				ctx->fillText("-", 15 + (level*10), liftUp + (_elementHeight*(elementCount-1)));        
            } else {
                ctx->fillText("+", 15 + (level*10), liftUp + (_elementHeight*(elementCount-1)));
            }
            //ctx.font = 8 + "pt Calibri";
        } else {
             ctx->SetFillStyle(0.9f, 0.9f, 0.9f);
        }
        
        if(node->draggable) {
           ctx->SetFillStyle(0.9f, 0.9f, 0.9f);
        }
        
		/*
        if(node->highlight) {
            ctx.fillStyle = "#FFFF00";
        }
		*/
        
         ctx->fillText(node->_name, 30 + (level*10), liftUp + (_elementHeight*(elementCount-1)));

        //
        std::vector<TreeListNode*> childs = node->_childs;
		if(childs.size() != 0 && isElementOpen) {
            for(int i = 0; i < childs.size(); i++) {
                TreeListNode* child = childs[i];
                elementCount = ParseObjectTree_draw(child, ctx, elementCount, (level+1));
            }
        }

        return elementCount;
    }

}